Generated code - Databinding with ASP.NET Web forms, Adapter
Preface
In ASP.NET web forms, databinding is fully 2-way, and can be setup declaratively, which
means you can setup databinding completely in HTML, without the necessity of code in the code-behind file. This section is about databinding with a set of
data using a
DataSource control.
LLBLGen Pro datasource controls
The
LLBLGen Pro runtime framework ships with its own DataSourceControl controls:
LLBLGenProDataSource for selfservicing and
LLBLGenProDataSource2
for adapter. These also are located in the
SD.LLBLGen.Pro.ORMSupportClasses.Web dll.
To use them at design time, you have to add them to the toolbox first. This can be done manually by right-clicking the toolbox when a web form is open in the
VS.NET editor (HTML or design view)
and then by selecting 'Choose items...' which allows you to browse to the
SD.LLBLGen.Pro.ORMSupportClasses.Web dll.
Getting started with the LLBLGenProDataSource2 control
Dragging the datasource control of choice onto a form in design mode will show you the smart tag to configure the datasource. The
LLBLGenProDataSource2 control can be used for an
EntityCollection<T>,
TypedList or
TypedView.
It's recommended you use the smart-tag to setup the
LLBLGenProDataSource2
control in the web form designer. To learn more about the specific properties of the
LLBLGenProDataSource2 control, please consult the LLBLGen Pro reference manual for the
LLBLGenProDataSource2 control.
The
LLBLGenProDataSource2 control accepts a type specification which is used for the particular container type: so
an entity factory for the
EntityCollection<T>, the type of a
TypedList or the type of a
TypedView. The container type, thus what kind of object is contained
in the
LLBLGenProDataSource2 control, is specified using the property
DataContainerType, accessable in the designer for the
LLBLGenProDataSource2 control
and also in the property grid of VS.NET. The contained object itself is exposed through the property
belonging to the value of this property: so if the
DataContainerType is set to
EntityCollection, an
EntityCollection<T> is inside the
LLBLGenProDataSource2
control and the
EntityCollection property is valid, though when
DataContainerType is set to
TypedList, a
TypedList object is contained
by the
LLBLGenProDataSource2 control, the
TypedList property is
valid.
The
GroupBy property is suppored in TypedList/TypedView scenario's while Prefetch path objects
(settable through the
PrefetchPathToUse property) are supported in EntityCollection scenarios.
Caching of data.
The data contained by the
LLBLGenProDataSource2 control is cached in-between post-backs,
until the data has to be refreshed. If caching is enabled (default), the place where this data is cached is either in the
ViewState (default), ASP.NET cache or the Session. You can control where the
data is cached by setting the
LLBLGenProDataSource2 control's property
CacheLocation.
You can disable this caching by setting the
CacheLocation property
to
None. If
CacheLocation is set to
Session, the data is stored in the session object with a key with the following name:
__LLBLGENPRODATASOURCEDATA_controlUniqueID_BindingContainerName
ControlUniqueID is the UniqueID of the DataSource control on the page.
BindingContainerName is the name of the container the control is located in. This key is stored in the control state and is always preserved.
If the
CacheLocation is set to ASPNetCache, the data is stored in the ASP.NET Cache using the following key:
__LLBLGENPRODATASOURCEDATA_Guid
where the
Guid is a new Guid per
LLBLGenProDataSource2 control
instance. You can control the ASP.NET Cache duration as well by using the property
ASPNetCacheDuration which indicates in minutes the time the cached data should stay in the
ASP.NET cache. Default is 20 minutes.
Disabling caching, by setting it to DataSourceCacheLocation.None, has the effect that if the
LLBLGenProDataSource2 control is forced to fetch data by a call to
ExecuteSelect, it always will refetch the data from the database. This can lead to different data in the page
between post-backs (pre post-back and post post-back), so you should be
aware of this when using the None setting. As no data is cached, a bound
control should use the data in a read-only fashion. When
CacheLocation
is set to None, the
LLBLGenProDataSource2 control will still cache its
own state in the ASP.NET control state.
Setting the data container manually.
The controls offer properties (EntityCollection, TypedList, TypedView) to set the contained object to an external object, for example an
EntityCollection<T>
object you've fetched in a method in your business logic tier. This also offers
e.g. the ability to bind myCustomer.Orders to grids through the datasource controls by simply setting the property
EntityCollection in the code behind file of the web form. You can do
this too with TypedLists by setting the
TypedList property and with TypedViews by setting the
TypedView property. Be sure to first set the
DataContainerType
property to the right container type, i.e. EntityCollection, TypedList or TypedView.
Two way databinding.
Two way databinding can be done with the DataContainerType set to
EntityCollection. This means the
LLBLGenProDataSource2 control manages not only the
binding of data to a control but also the manipulation of data through the bound control (e.g. a GridView) of the data in the contained
EntityCollection<T>. As
TypedList and
TypedView classes are read-only by definition, you can't manipulate data inside these classes through the
LLBLGenProDataSource2 control. How the
LLBLGenProDataSource2 control fetches data (automatically or through code placed inside an eventhandler) as well as how it saves data (automatically or through
event handlers) is discussed in the next section.
LivePersistence and events
A boolean property of the
LLBLGenProDataSource2 control, called
LivePersistence, is used to signal the
LLBLGenProDataSource2 control
to perform the select, insert, update and delete actions directly on the database (true) or modify the entity collection and add the actions to a Unit
of Work object
(false).
If
LivePersistence is set to false, fetching data and saving data isn't performed by the
LLBLGenProDataSource2 control but an event is raised instead
which passes an event arguments object which contains the parameters for the fetch or save and allows
your own code to perform the fetch or save. Also, the changed event is raised so the bound control(s) can refetch the data from the
LLBLGenProDataSource2 control.
LivePersistence causes 3 events to be raised:
- PerformSelect. This event is raised when the LLBLGenProDataSource2
control needs to retrieve data from the database. Use the passed-in PerformSelectEventArgs2 object to perform the Fetch action. You should fetch the data into the appropriate object inside the
PerformSelectEventArgs2 object, for example the ContainedCollection
using the parameters available in the PerformSelectEventArgs2
object.
- PerformGetDbCount. This event is raised when the LLBLGenProDataSource2
control needs to retrieve the number of items in the complete resultset. This event is raised when server side paging is enabled and the total number of items in the resultset is required by the bound control(s). Your handler should fetch the count of the set to fetch by using the passed in PerformGetDbCountEventArgs2 object which contains all information necessary for the retrieval of the count value. Set the DbCount property of the
PerformGetDbCountEventArgs2 object to the value read from the database. Be sure to pass to the DataAccessAdapter.GetDbCount
call the filter, prefetch path, sort expression and other objects available to you via the passed-in
PerformGetDbCountEventArgs2 object.
- PerformWork. This event is raised when ExecuteInsert/Update/Delete is called on the
LLBLGenProDataSource2 control by a bound control.
Typically this is done after an entity is edited in a GridView or FormView control for example, or a new entity is added through a bound control.
The work is tracked in a UnitOfWork2 object which is available to you in the passed in PerformWorkEventArgs2 object.
When a refetch of the data has taken place, the
UnitOfWork2 object contained in the control is cleared. This means that any update/insert/delete work pending has
to be completed by that point.
Please examine the events and special event argument classes in the LLBLGen Pro
Reference manual.
Refetch
To ensure fresh data from the database is retrieved, a flag on the
LLBLGenProDataSource2
called
Refetch can be set to true, so the control
will refetch the data, even if for example the page number is the same. This can be necessary if the code-behind code decides the data represented by the
LLBLGenProDataSource2 control is invalidated and has to be refetched from the database.
Using the LLBLGenProDataSource2 control.
Binding a
LLBLGenProDataSource2 control works like any other web
form DataSourceControl: just add the ID as DataSourceID in the bound control's HTML, or select the
LLBLGenProDataSource2 control from
the dropdown box for available datasources in the bound control's smart-tag. The designer of the
LLBLGenProDataSource2 control will allow the user to select
the
DataAccessAdapter, the DataContainerType and the type of object needed for the container (factory, typedlist or typedview type).
By default no filter is set, no groupby, no prefetch
path, no sorting. To set a filter, prefetch path or sort expression, a code behind page is required to set these parameters. This is due to the requirement that these are
compile time checked. You can however also produce filters at runtime by using the ASP.NET parameter binding feature. This allows you to setup a binding between a
control (or cookie, form etc.) which produces a value and the datasource control so the value produced by the other control is used for filtering.
See the example below which uses two drop down boxes to create a filter at runtime for fetching data.
Paging is supported as well: if you want server-side paging,
define the paging parameters on the
LLBLGenProDataSource2 in the VS.NET property grid. If you want paging inside your bound control
(client-side paging), define the
paging parameters in the bound control, e.g. the GridView. To be able to work with paging, you of course have to enable paging on the bound control.
The PerformWork event in an AJAX environment
When you use a grid like the DevExpress ASPxGrid for .NET, you can have all edit activities on the client side, using AJAX communication with the server. When
you've setup the grid to be used on the client side, and the
LLBLGenProDataSource2
control has
LivePersistence set to false, the changes made to the data on the
client will be performed in one go when the page gets a post-back. In this scenario, it's more efficient not to bind to
PerformWork, but to place a button on the
form which simply performs the 'save', e.g. it says "Save changes". By not binding to the
PerformWork event, all ExecuteInsert/Update/Delete actions will take place
on the data, but aren't propagated to the database just yet, because
LivePersistence
is set to false. In the button handler of your save button, you then retrieve
the UnitOfWork2 object from the
LLBLGenProDataSource2 control from
the property
UnitOfWorkObject,
which contains all changes made and you can commit the changes in one transaction.
Filtering on the fly
The
LLBLGenProDataSource2 control supports filtering on the fly based on parameters specified which can retrieve values from other controls, forms,
cookies or other objects supported by the SelectParameters feature of ASP.NET.
This is available in a
LLBLGenProDataSource2 control via its
SelectParameters property. The
SelectParameters property follows the same specification as the ObjectDataSource and are specified declaratively using the
<SelectParameters> HTML elements inside a
LLBLGenProDataSource2 control declaration. You can also use the VS.NET designer for setting up the
SelectParameters, to do that
simply click the [...] button next to
SelectParameters in the Property grid of VS.NET. Be sure that the parameter name has the
same name as a field in the
entity, typed list row or typed view row. You can't use
SelectParameters
to build a filter on non-entity fields as it builds a filter for the
next fetch.
Trapping invalid input values
As the
LLBLGenProDataSource2 control is the receiver of the data filled into a form, grid or other bound control, it can be these values are invalid, for example they don't match the type of the entity field or they are too big in size. By default, the
LLBLGenProDataSource2 control will ignore these values and won't throw an exception. To make the control throw an exception after all values have been evaluated, you can set the
LLBLGenProDataSource2 property
ThrowExceptionOnIllegalFieldInput to true, which signals the control to throw an exception if one or
more fields received an illegal value which wasn't convertible to the type of the field in an update/insert scenario. If set to true all illegal values are collected and added to one single
ORMValueTypeMismatchException
so your code will receive just one exception to handle them all. If set to
false, the illegal values are ignored and the fields don't get set to a new
value.
Usage examples
Below are two examples: one example using
LivePersistence set to true and one using
LivePersistence set to false. They're basically the same form. For VB.NET users: the HTML is for C#, you've to change the first line of the given HTML snippets into the following line to use it with VB.NET:
<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="_Default" %>
Example using LivePersistence
This example contains a
form, which filters a list of Order entities, provided by the
LLBLGenProDataSource2
control
orderDS, on the
OrderEntity field
ShippingCountry, provided by a static drop down box, and a drop down box with all customers from Northwind, provided by
LLBLGenProDataSource2 control
customerDS. Using parameter binding the two dropdown boxes produce filter information at runtime to produce the proper order list. No code required,
it's completely declarative HTML.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses.Web"
Namespace="SD.LLBLGen.Pro.ORMSupportClasses" TagPrefix="llblgenpro" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
All customers:<br />
Customers:
<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="customerDS"
DataTextField="CompanyName" DataValueField="CustomerId" AutoPostBack="True">
</asp:DropDownList><br />
ShipCountry:
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True">
<asp:ListItem>Spain</asp:ListItem>
<asp:ListItem>Germany</asp:ListItem>
</asp:DropDownList><br />
<llblgenpro:llblgenprodatasource2 id="customerDS" runat="server"
cachelocation="Session" datacontainertype="EntityCollection" enablepaging="True"
AdapterTypeName="NW20.DatabaseSpecific.DataAccessAdapter, NW20DBSpecific"
EntityFactoryTypeName="NW20.FactoryClasses.CustomerEntityFactory, NW20">
</llblgenpro:llblgenprodatasource2>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="orderDS"
DataKeyNames="OrderId" AllowPaging="True" PageSize="5">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="ShipAddress" HeaderText="ShipAddress" SortExpression="ShipAddress" />
<asp:BoundField DataField="ShipName" HeaderText="ShipName" SortExpression="ShipName" />
<asp:BoundField DataField="ShipCountry" HeaderText="ShipCountry" SortExpression="ShipCountry" />
<asp:BoundField DataField="CustomerId" HeaderText="CustomerId" SortExpression="CustomerId" />
<asp:BoundField DataField="ShipRegion" HeaderText="ShipRegion" SortExpression="ShipRegion" />
<asp:BoundField DataField="ShipCity" HeaderText="ShipCity" SortExpression="ShipCity" />
<asp:BoundField DataField="OrderId" HeaderText="OrderId" SortExpression="OrderId" />
<asp:BoundField DataField="ShipPostalCode" HeaderText="ShipPostalCode" SortExpression="ShipPostalCode" />
</Columns>
</asp:GridView>
<llblgenpro:llblgenprodatasource2 id="orderDS" runat="server" cachelocation="Session"
datacontainertype="EntityCollection" enablepaging="True"
AdapterTypeName="NW20.DatabaseSpecific.DataAccessAdapter, NW20DBSpecific"
EntityFactoryTypeName="NW20.FactoryClasses.OrderEntityFactory, NW20">
<SelectParameters>
<asp:ControlParameter ControlID="DropDownList1" Name="CustomerId"
PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="DropDownList2" Name="ShipCountry"
PropertyName="SelectedValue" Type="String" />
</SelectParameters>
</llblgenpro:llblgenprodatasource2>
</form>
</body>
</html>
Example using Perform Event handlers
The following example is the same form as in the previous example, with the same functionality, however now it uses
LivePersistence set to false, which means we've to perform the persistence logic ourselves by writing event handlers. The HTML is shown first, which is roughly the same as the previous example's HTML except it defines bindings to EventHandlers for
PerformGetDbCount,
PerformSelect and
PerformWork. After that the code behind in VB.NET and C# is shown.
HTML page
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses.Web"
Namespace="SD.LLBLGen.Pro.ORMSupportClasses" TagPrefix="llblgenpro" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
All customers:<br />
Customers:
<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="customerDS"
DataTextField="CompanyName" DataValueField="CustomerId" AutoPostBack="True">
</asp:DropDownList><br />
ShipCountry:
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True">
<asp:ListItem>Spain</asp:ListItem>
<asp:ListItem>Germany</asp:ListItem>
</asp:DropDownList><br />
<llblgenpro:llblgenprodatasource2 id="customerDS" runat="server"
cachelocation="Session" datacontainertype="EntityCollection" enablepaging="True"
AdapterTypeName="NW20.DatabaseSpecific.DataAccessAdapter, NW20DBSpecific"
EntityFactoryTypeName="NW20.FactoryClasses.CustomerEntityFactory, NW20"
LivePersistence="False" OnPerformSelect="customerDS_PerformSelect">
</llblgenpro:llblgenprodatasource2>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="orderDS"
DataKeyNames="OrderId" AllowPaging="True" PageSize="5">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="ShipAddress" HeaderText="ShipAddress" SortExpression="ShipAddress" />
<asp:BoundField DataField="ShipName" HeaderText="ShipName" SortExpression="ShipName" />
<asp:BoundField DataField="ShipCountry" HeaderText="ShipCountry" SortExpression="ShipCountry" />
<asp:BoundField DataField="CustomerId" HeaderText="CustomerId" SortExpression="CustomerId" />
<asp:BoundField DataField="ShipRegion" HeaderText="ShipRegion" SortExpression="ShipRegion" />
<asp:BoundField DataField="ShipCity" HeaderText="ShipCity" SortExpression="ShipCity" />
<asp:BoundField DataField="OrderId" HeaderText="OrderId" SortExpression="OrderId" />
<asp:BoundField DataField="ShipPostalCode" HeaderText="ShipPostalCode" SortExpression="ShipPostalCode" />
</Columns>
</asp:GridView>
<llblgenpro:llblgenprodatasource2 id="orderDS" runat="server" cachelocation="Session"
datacontainertype="EntityCollection" enablepaging="True"
AdapterTypeName="NW20.DatabaseSpecific.DataAccessAdapter, NW20DBSpecific"
EntityFactoryTypeName="NW20.FactoryClasses.OrderEntityFactory, NW20" LivePersistence="False"
OnPerformGetDbCount="orderDS_PerformGetDbCount" OnPerformSelect="orderDS_PerformSelect"
OnPerformWork="orderDS_PerformWork">
<SelectParameters>
<asp:ControlParameter ControlID="DropDownList1" Name="CustomerId"
PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="DropDownList2" Name="ShipCountry"
PropertyName="SelectedValue" Type="String" />
</SelectParameters>
</llblgenpro:llblgenprodatasource2>
</form>
</body>
</html>
Code behind
// C#
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using SD.LLBLGen.Pro.ORMSupportClasses;
using NW20.DatabaseSpecific;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void customerDS_PerformSelect(object sender, PerformSelectEventArgs2 e)
{
// fetch all customers using the information passed in via the
// PerformSelectEventArgs2 object. This select doesn't have to perform any paging, as the
// data is for a combo box.
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
adapter.FetchEntityCollection(e.ContainedCollection, e.Filter,
e.MaxNumberOfItemsToReturn, e.Sorter, e.PrefetchPath);
}
}
protected void orderDS_PerformGetDbCount(object sender, PerformGetDbCountEventArgs2 e)
{
// get the total number of orders which match the filter passed in via the
// PerformGetDbCountEventArgs2.
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
e.DbCount = adapter.GetDbCount(e.ContainedCollection, e.Filter);
}
}
protected void orderDS_PerformSelect(object sender, PerformSelectEventArgs2 e)
{
// fetch all orders which are in the selected page using the filter passed in
// via the PerformSelectEventArgs2 object.
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
adapter.FetchEntityCollection(e.ContainedCollection, e.Filter,
e.MaxNumberOfItemsToReturn, e.Sorter, e.PrefetchPath,
e.PageNumber, e.PageSize);
}
}
protected void orderDS_PerformWork(object sender, PerformWorkEventArgs2 e)
{
// Perform the work passed in via the PerformWorkEventArgs2 object.
// Start a new transaction with the passed in unit of work.
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
// pass the adapter to the Commit routine and tell it to autocommit
// when the work is done.
e.Uow.Commit(adapter, true);
}
}
}
' VB.NET
Imports SD.LLBLGen.Pro.ORMSupportClasses
Imports NW20.DatabaseSpecific
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub customerDS_PerformSelect(ByVal sender As Object, ByVal e As PerformSelectEventArgs2) _
Handles customerDS.PerformSelect
' fetch all customers using the information passed in via the
' PerformSelectEventArgs2 object. This select doesn't have to perform any paging, as the
' data is for a combo box.
Using adapter As New DataAccessAdapter()
adapter.FetchEntityCollection(e.ContainedCollection, e.Filter, _
e.MaxNumberOfItemsToReturn, e.Sorter, e.PrefetchPath)
End Using
End Sub
Protected Sub orderDS_PerformGetDbCount(ByVal sender As Object, ByVal e As PerformGetDbCountEventArgs2) _
Handles orderDS.PerformGetDbCount
' get the total number of orders which match the filter passed in via the
' PerformGetDbCountEventArgs2.
Using adapter As New DataAccessAdapter()
e.DbCount = adapter.GetDbCount(e.ContainedCollection, e.Filter)
End Using
End Sub
Protected Sub orderDS_PerformSelect(ByVal sender As Object, ByVal e As PerformSelectEventArgs2) _
Handles orderDS.PerformSelect
' fetch all orders which are in the selected page using the filter passed in
' via the PerformSelectEventArgs2 object.
Using adapter As New DataAccessAdapter()
adapter.FetchEntityCollection(e.ContainedCollection, e.Filter, _
e.MaxNumberOfItemsToReturn, e.Sorter, e.PrefetchPath, _
e.PageNumber, e.PageSize)
End Using
End Sub
Protected Sub orderDS_PerformWork(ByVal sender As Object, ByVal e As PerformWorkEventArgs2) _
Handles orderDS.PerformWork
' Perform the work passed in via the PerformWorkEventArgs2 object.
' Start a new transaction with the passed in unit of work.
Using adapter As New DataAccessAdapter()
' pass the adapter to the Commit routine and tell it to autocommit
' when the work is done.
e.Uow.Commit(adapter, True)
End Using
End Sub
End Class
Setting values for insert/update using bound parameters
ASP.NET supports bound parameters, where you can define parameters which retrieve the values from other controls, cookies, query string etc.
One example is given above, using filtering based on the
SelectParameters. The
LLBLGenProDataSource2 control supports also
InsertParameters and
UpdateParameters.
You can define these parameters for insert (saving a new entity) and update
(saving a changed entity) resp. the same way as you do with
SelectParameters.
This way you can for example set the 'EmployeeId' on a new order entity where you
retrieve the EmployeeId from a dropdown control. The value retrieved through a parameter overrules a set value through the bound control. If no value is
passed in by the bound control and it's available through the
InsertParameters
(when inserting) or
UpdateParameters (when updating), the value in the
Insert/UpdateParameters collection is chosen.
Converting empty string values ("") to NULL values for inserts/updates
In a web-application, form values which are empty are represented as an empty string (""). When an entity is edited through a form, it can be some textboxes
or other controls bound to fields of the entity are left empty / point to an empty value: "". The
LLBLGenProDataSource2 control will convert "" into NULL
for all fields which .NET type isn't the string type. If the field
is the string type, this can give a problem: what if the empty string is a valid value?
To tell the
LLBLGenProDataSource2 control that a field should get the empty string as a valid value instead of NULL, you
have to pass a List<string> object
with all the fieldnames of the fields which should accept "" as the valid value to the property
FieldNamesKeepEmptyStringAsValue of the
LLBLGenProDataSource2 control. You should do this in the code behind of your webform.
Example
// C#
// in your Page Load handler routine
if( !Page.IsPostBack )
{
List<string> fieldsWhichShouldKeepEmptyString = new List<string>();
fieldsWhichShouldKeepEmptyString.Add( "ShipAddress" );
_ordersDS.FieldNamesKeepEmptyStringAsValue = fieldsWhichShouldKeepEmptyString;
}
' VB.NET
' in your Page Load handler routine
If Not Page.IsPostBack Then
Dim fieldsWhichShouldKeepEmptyString As New List(Of String)()
fieldsWhichShouldKeepEmptyString.Add( "ShipAddress" )
_ordersDS.FieldNamesKeepEmptyStringAsValue = fieldsWhichShouldKeepEmptyString
End If
This example tells the
LLBLGenProDataSource2 control called '_ordersDS' that the field
ShipAddress should get the value "" instead of NULL
if the form value is "" for that field.
Normally you don't need to set the property
FieldNamesKeepEmptyStringAsValue, if "" is not used for string values and NULL is acceptable instead.
It can be that the list of names which keep the empty string as the value is actually the complete set of fields of the entity. In that case, you can set the property
AllFieldsKeepEmptyStringAsValue to true, which makes the
LLBLGenProDataSource2 control to simply not convert empty strings to NULL values for entity fields. Setting this property to true will make
LLBLGenProDataSource2 control to ignore
FieldNamesKeepEmptyStringAsValue.
The SortingMode property
The
LLBLGenProDataSource2 control is capable to apply sorting when data has to be fetched, or for example when you've clicked a column header in a
bound GridView control. By default, the
LLBLGenProDataSource2 control sorts on the server-side, by producing a
SortExpression which is then used by the fetch
logic. Which
SortExpression is used depends on the value of the property
SorterToUse of the
LLBLGenProDataSource2 control and the columns specified
by the bound control (e.g. clicked column header). It's possible to tell the
LLBLGenProDataSource2 control to sort on the
client-side instead. Do
this by setting the
LLBLGenProDataSource2 property
SortingMode.
By default this is set to ServerSide. If you set it to ClientSide, sorting is applied after the fetch, by sorting the DefaultView object of the
LLBLGenProDataSource2.
Server-side sorting only uses EntityField2 objects, so if the entity has a field which isn't a field mapped onto a table/view field, it's ignored in the
server-side sorting actions because it's not part of the query send to the database. This is also true for fields mapped onto related fields. In these
situations, use client-side sorting.
Be aware that if the
CacheLocation is set to None, the
LLBLGenProDataSource2
control always has to fetch the data from the database again, as it can't sort cached data in-memory. If you want to avoid the roundtrip
to the database, set
CacheLocation to another value than None.